from datetime import datetime

from database import db
from errors import Duplicate, Missing
from sqlalchemy.exc import IntegrityError

from data.models import ClientParking


def _create_client_parking(
    client_id: int, parking_id: int, time_in: datetime = datetime.now()
) -> ClientParking:
    client_parking = ClientParking(
        client_id=client_id, parking_id=parking_id, time_in=time_in
    )
    db.session.add(client_parking)

    try:
        db.session.commit()
    except IntegrityError as ex:
        db.session.rollback()
        if "FOREIGN KEY" in str(ex):
            # SQLite reports "FOREIGN KEY constraint failed" if client_id/parking_id do not exist
            raise Missing(msg="Non-existent client_id or parking_id") from ex
        else:
            raise Duplicate(
                msg=(
                    f"Client client_id={client_id} already "
                    f"parked at parking_id={parking_id}"
                )
            ) from ex

    return client_parking


def create_client_parking_json(
    client_id: int, parking_id: int, time_in: datetime = datetime.now()
) -> dict:
    return _create_client_parking(client_id, parking_id, time_in).to_json()


def _update_client_parking(
    client_id: int, parking_id: int, time_out: datetime
) -> ClientParking:
    """Устанавливает значение time_out в записи по идентификаторам client_id, parking_id
    :returns обновленный инстанс ClientParking
    """
    client_parking: ClientParking = (
        db.session.query(ClientParking)
        .where(
            (ClientParking.client_id == client_id)
            & (ClientParking.parking_id == parking_id)
        )
        .scalar()
    )

    if not client_parking:
        raise Missing(
            msg=f"ClientParking for client_id={client_id}, parking_id={parking_id} not found"
        )

    client_parking.time_out = time_out
    db.session.commit()

    return client_parking


def update_client_parking_json(
    client_id: int, parking_id: int, time_out: datetime
) -> dict:
    return _update_client_parking(client_id, parking_id, time_out).to_json()


def delete_client_parking(client_id: int, parking_id: int) -> None:
    row_count = (
        db.session.query(ClientParking)
        .where(
            (ClientParking.client_id == client_id)
            & (ClientParking.parking_id == parking_id)
        )
        .delete()
    )

    if row_count == 0:
        raise Missing(
            msg=f"ClientParking for client_id={client_id}, parking_id={parking_id} not found"
        )
